﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;

namespace Xts
{
    namespace Util
    {
        public class XProducerConsumer : IDisposable
        {
            protected XThreadSafeQueue<IXRequestJob> x_JobQueue;
            protected List<Thread> x_JobReaderThreadSet;
            protected bool x_bIsRunning;

            public bool IsRunning { get { return x_bIsRunning; } }

            public XProducerConsumer()
            {
                x_bIsRunning = false;
                x_JobQueue = new XThreadSafeQueue<IXRequestJob>();
                x_JobReaderThreadSet = new List<Thread>();
                
            }

            #region Dispose Resources
            public void Dispose()
            {
                Dispose(true);
                //take us off of the finalization queue
                GC.SuppressFinalize(this);
            }

            protected virtual void Dispose(bool disposing)
            {
                if (!this.disposed)
                {
                    if (disposing)
                    {
                        //dispose of managed resources......
                        StopReaderThreads();
                        x_JobQueue.Clear();
                        x_JobReaderThreadSet.Clear();

                    }
                    //dispose of unmanaged resources......
                    disposed = true;
                }
            }

            ~XProducerConsumer() { Dispose(false); }
            private bool disposed = false;
            #endregion

            public void StartReaderThreads(uint n)
            {
                if (IsRunning)
                    return;

                for (uint i = 0; i < n; i++)
                {
                    XRequestReaderThread readerThread = new XRequestReaderThread(ref x_JobQueue);
                    Thread t = new Thread(new ThreadStart(readerThread.Run));
                    t.Start();
                    x_JobReaderThreadSet.Add(t);
                }

                x_bIsRunning = true;
            }

            public void StopReaderThreads()
            {
                if (!IsRunning)
                    return;

                for (int i = 0; i < x_JobReaderThreadSet.Count; i++)
                {
                    IXRequestJob endingJob = new XEndingReaderJob();
                    x_JobQueue.Enqueue(endingJob);
                }

                foreach (Thread t in x_JobReaderThreadSet)
                {
                    t.Join();
                }
                x_bIsRunning = false;
            }

            public void NewRequestJob(ref IXRequestJob req)
            {
                x_JobQueue.Enqueue(req);
            }

        }
    }
}